#include "YModemPublic.h"
/*** Interior Define */

#define LLOG_ERR
// #define LLOG_MARK
#define LLOG
#include "llog.h"

#ifdef	CFG_SYS_MALLOC

#define L_MALLOC 	MALLOC
#define L_FREE 		MFREE

#else

#include <stdlib.h>
#define L_MALLOC(A) malloc(A)
#define L_FREE(A)	free(A)

#endif

/*** Interior Struct */
struct CC_YModem_Ptcl_Recognition{
	/***
		DataPkg CmdH[]+Sn[]+XSn[]+D[128 or 1024]+CRC16[]
		CodePkg Code[]
	*/
	uint8_t 	Cmd			; 	// 
	uint8_t		Sn			;
	uint8_t		NSn			;	// 取反
	uint16_t	CRC16		;   
	uint16_t	CalcCRC16	;   
	
	uint16_t 	Len			;	// ParaLen
	
	uint16_t  	i			;	// 接收数据缓存偏址
    uint8_t   	step		;	// 状态
    uint16_t  	RBufSz		;	
    uint8_t*  	pBuf		;  
	
    uint32_t 	LastTick;    	
    uint32_t 	ToutMs;      	// 接收字节间(ByteIntervalTime)时间超时
	
	//
	int (*pPkgParser)(uint32_t RBufSz,uint8_t* pBuf) 	; 
	// int (*pPkgParser)(void* pPara,uint32_t RBufSz,uint8_t* pBuf) 	; 
	// void* pPara;
};

/*** Global Data */

/*** Local Function Define*/

//========================//
#ifdef CFG_RECO_YM // || CFG_YMM

uint16_t Calc_CRC16_ByByte(uint16_t crc,unsigned char ch){

	int i;
	uint16_t POLY=0x1021;
	
	crc=crc^(ch<<8);
	for(i=0;i<8;i++){		
		if(crc & 0x8000){
			crc=(crc<<1)^POLY;
		}
		else{
			crc<<=1;
		}
	}
	crc=crc&0xFFFF;
	return crc;
}

#endif

#ifdef CFG_RECO_YM 

int RecoYM_Recognizer(void* pObj,uint8_t ch){
	// 
	uint8_t   	State;
    int ret=RET_ERR;
    tReco_YModem* pTObj;
	
	if(pObj == NULL)			{ LLOG_ERR(); return ret; }

    pTObj=(tReco_YModem*)pObj;
	
	if(pTObj->pBuf == NULL)		{ LLOG_ERR(); return ret; }
	if(pTObj->RBufSz == NULL)	{ LLOG_ERR(); return ret; }

    if(Check_TimeOut(pTObj->LastTick, pTObj->ToutMs) == RET_OT){
		pTObj->step = 0; LLOG_ERR();
    }
    pTObj->LastTick=GetNowTick();

    // TODO:  
	State = pTObj->step;
    switch (State){
		case 0:{
			pTObj->Len = 0;
			switch(ch){
				case RYM_CODE_SOH  : { pTObj->Len = RYM_SOH_PKG_SZ; }break;
				case RYM_CODE_STX  : { pTObj->Len = RYM_STX_PKG_SZ; }break;
				case RYM_CODE_EOT  : { pTObj->Len = 1; }break;
				case RYM_CODE_ACK  : { pTObj->Len = 1; }break;
				case RYM_CODE_NAK  : { pTObj->Len = 1; }break;
				case RYM_CODE_CAN  : { pTObj->Len = 1; }break;
				case RYM_CODE_C    : { pTObj->Len = 1; }break;
				default :{
					LLOG("#E RecoYM ch[%x]\n",ch);
					State = 0; LLOG_MARK(); 					
				}
			}
			if(pTObj->Len > 0){
				pTObj->Cmd= ch;
				if(pTObj->Len == 1){	// TODO: CodePkg 
					pTObj->i=0;
					pTObj->pBuf[pTObj->i++] = pTObj->Cmd;
					ret=RET_OK;
					
					State = 0; LLOG_MARK(); //
				}
				else{
					pTObj->CalcCRC16 = 0;
					State++;
				}
			}
		}break;
		case 1:{
			pTObj->Sn= ch;
			State++;
			
		}break;
		case 2:{
			pTObj->NSn= ch;
			if( (pTObj->Sn) == ((pTObj->NSn)^0xFF)){
				pTObj->i=0;
				pTObj->pBuf[pTObj->i++] = pTObj->Cmd;
				pTObj->pBuf[pTObj->i++] = pTObj->Sn;			
				pTObj->pBuf[pTObj->i++] = pTObj->NSn;
				State++;
			}
			else{
				State = 0; LLOG_MARK();
			}
		}break;	
		case 3:{
			if ( pTObj->i < (pTObj->Len-2) ){
				pTObj->pBuf[pTObj->i++] = ch;
				
				pTObj->CalcCRC16 = Calc_CRC16_ByByte(pTObj->CalcCRC16,ch);
				
				if(pTObj->i == (pTObj->Len-2)){
					State++;
				}
			}
			else{	// 帧超长 reset
				State = 0;LLOG_MARK(); 
			}
		} break;
		case 4:{
			pTObj->CRC16=ch;
			pTObj->CRC16<<=8;
			State++;
			pTObj->pBuf[pTObj->i++] = ch;
		}break;
		case 5:{
			pTObj->CRC16+=ch;
			if(pTObj->CalcCRC16 == pTObj->CRC16){
				pTObj->pBuf[pTObj->i++] = ch;
				ret = RET_OK; 
			}
			else{
				LLOG_MARK();
			}
			State = 0;
		}break;
		default:{
			State = 0;
		}
		
    }
	
	pTObj->step = State;
	// 
	if((ret == RET_OK) && (pTObj->pPkgParser != NULL) ){
		pTObj->pPkgParser(pTObj->Len,pTObj->pBuf);
	}

    return ret;
}

tReco_YModem* RecoYM_Create(uint16_t RBufSz){
	
	tReco_YModem* ptmp=NULL;
	uint8_t* pBuf;
	uint32_t AllocSz;
	uint32_t ObjSz;
	
	ObjSz = sizeof(tReco_YModem);
	AllocSz=(ObjSz&0x03)?4:0;
	AllocSz+=ObjSz&(~0x03);

	pBuf = L_MALLOC(AllocSz+RBufSz);
	if(pBuf == NULL)	{ LLOG_ERR(); return ptmp; }
	
	MEMSET(pBuf,0,AllocSz+RBufSz);
	ptmp=(tReco_YModem*)&pBuf[0];	
	//
	ptmp->RBufSz 	= RBufSz	;
	ptmp->pBuf		= &pBuf[AllocSz]	;
	ptmp->ToutMs	= 100	;
	ptmp->step		= 0		;
	
	return ptmp;
}

int RecoYM_Set_MsTimOut(tReco_YModem* pObj,uint32_t Para_TimeOut){
	int ret=RET_ERR;
	if(pObj == NULL) { LLOG_ERR(); return ret; }
	ret=RET_OK;
	
	pObj->ToutMs		= Para_TimeOut	;
	return ret;
}

int RecoYM_BindParser(tReco_YModem* pObj,int (*pPkgParser)(uint32_t ,uint8_t* )){
	int ret=RET_ERR;
	if(pObj == NULL) { LLOG_ERR(); return ret; }
	ret=RET_OK;
	
	pObj->pPkgParser		= pPkgParser	;
	return ret;
}

#endif

#ifdef CFG_YMM

uint16_t Calc_Pkg_CRC16(uint16_t InitCRC,uint16_t Len,uint8_t* pPkg){
	uint16_t crc;
	int i;
	crc=InitCRC;
	for(i=0;i<Len;i++)
		crc=Calc_CRC16_ByByte(crc,pPkg[i]);
	
	return crc;
}

int u32ToHexStr(uint32_t Val,uint8_t* pRbuf){
	
	uint8_t Flag=1;
	uint8_t tmp=0;
	int i;
	int j; 
	uint8_t HexStr[]="0123456789ABCDEF";
	
	j=0;
	for(i=0;i<8;i++){
		tmp=(Val>>(32-4*(i+1)))&0x0F;
		if(Flag && (tmp == 0)){
			//pass
		}
		else{
			Flag=0;
			pRbuf[j++]=HexStr[tmp];
		}
	}
	pRbuf[j++]=0x00;
		
	return j;
}

int u32ToDecStr(uint32_t Val,uint8_t* pRbuf){
	
	uint8_t tmp=0;
	int i;
	int j;
	uint8_t DecStr[]="0123456789";
	uint8_t DecBuf[12];
	
	j=0;
	while(Val>0){
		tmp=Val%10;
		DecBuf[j++]=DecStr[tmp];
		if(Val<10){
			break;
		}
		Val=Val/10;
	}
	//str 翻转
	for(i=0;i<j;i++){
		pRbuf[i]=DecBuf[j-1-i];
	}
	pRbuf[j++]=0x00;
	return j;
}

#endif

#ifdef CFG_YMS			
uint32_t HexStrToU32(uint8_t* pStr){
	
	uint32_t tmp32;
	uint32_t tmp;
	int i;

	tmp32=0;
	i=0;
	while(pStr[i]!=0x00 && (i<8))
	{
		tmp=pStr[i++];
		//
		if( ('0'<= tmp) && (tmp <='9')){
			tmp-='0';
		}
		else if( ('a'<= tmp) && (tmp <='f')){
			tmp-=('a'-10);
		}
		else if( ('A'<= tmp) && (tmp <='F')){
			tmp-=('A'-10);
		}
		else{ // Err
			tmp32=0;LLOG_MARK();
		}
		tmp32<<=4;
		tmp32|=tmp&0x0f;
	}	
	return tmp32;
}

uint32_t DecStrToU32(uint8_t* pStr){
	
	uint32_t tmp32;
	uint32_t tmp;
	int i;

	tmp32=0;
	i=0;
	while(pStr[i]!=0x00 && (i<10)){
		tmp=pStr[i++];
		// 
		if( ('0'<= tmp) && (tmp <='9')){
			tmp-='0';
		}
		else{ // Err
			LLOG_ERR();
			tmp32=0;
			break;
		}
		tmp32*=10;
		tmp32+=tmp;
	}	
	return tmp32;
}

#endif




